from django.db import transaction
from django.utils import timezone
from decimal import Decimal
from django_redis import get_redis_connection
from rest_framework import serializers

from celery_tasks.html.tasks import generate_static_sku_detail_html
from goods.models import SKU
from orders.models import OrderInfo, OrderGoods

class Comment_ListSerializers(serializers.ModelSerializer):
    is_commented = serializers.BooleanField(read_only=True)

    class Meta:
        model = OrderGoods
        fields = ['is_anonymous', 'is_commented', 'score', 'comment']

    def update(self, instance, validated_data):
        order_id = self.context['pk']
        sku_obj = instance.sku
        score = validated_data.get('score')
        is_anonymous = validated_data.get('is_anonymous')
        comment = validated_data.get('comment')
        instance.comment = comment
        instance.is_commented = True
        instance.score = score
        instance.is_anonymous = is_anonymous
        instance.save()
        sku_obj.comments += 1
        sku_obj.save()
        if not OrderGoods.objects.filter(order_id=order_id, is_commented=0).count():
            OrderInfo.objects.filter(order_id=order_id).update(status=5)
        generate_static_sku_detail_html(instance.sku_id)
        return instance


class CommentSerializers(serializers.ModelSerializer):

    class Meta:
        model = OrderGoods
        fields = '__all__'

    # def update(self, instance, validated_data):
    #     instance.comment = validated_data['comment']
    #     instance.score = validated_data['score']
    #     instance.is_anonymous = validated_data['is_anonymous']
    #     instance.is_commented = True
    #     # instance.save()
    #     return instance



class SkuSerializer(serializers.ModelSerializer):
    class Meta:
        model = SKU
        fields = ('default_image_url','id','name')


class GoodsSerializer(serializers.ModelSerializer):
    sku = SkuSerializer(read_only=True)

    class Meta:
        model = OrderGoods
        fields = ('sku','price','comment','is_anonymous','is_commented','score')


class CartSKUSerializer(serializers.ModelSerializer):
    """
    购物车商品数据序列化器
    """
    count = serializers.IntegerField(label='数量')

    class Meta:
        model = SKU
        fields = ('id', 'name', 'default_image_url', 'price', 'count')


class OrderSettlementSerializer(serializers.Serializer):
    """
    订单结算数据序列化器
    """
    freight = serializers.DecimalField(label='运费', max_digits=10, decimal_places=2)
    skus = CartSKUSerializer(many=True)


class OrderCommitSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrderInfo
        fields = ('order_id', 'address', 'pay_method')
        read_only_fields = ('order_id',)
        extra_kwargs = {
            'address': {
                'write_only': True,
                'required': True,
            },
            'pay_method': {
                'write_only': True,
                'required': True
            }
        }
    """
        前端只是将 用户的token, address,pay方式提交给了我们
        我们需要 实现 订单信息以及订单商品列表数据的入库
        
        一.先实现 订单信息的保存
            1.1 接受地址信息
            1.2 接受支付方式
            1.3 接受用户信息
            1.4 生成订单id
            1.5 订单总数量和总价格(先为0)以及运费
            1.6 根据支付方式决定状态
        二,再去实现 订单商品列表的保存
            2.1 链接redis
            2.2 获取redis的数据 hash,set
            2.3 对redis数据进行转换,
                在转换呢过程中,只转换 选中的信息
                {sku_id:count}
            2.4 对选中商品信息的列表进行遍历
                2.5 根据商品id进行查询
                2.6 查询出来之后我们要根据商品的数量进行判断,库存是否充足
                2.7 库存减少,销量增加 
                2.8 遍历的过程中 累加商品数量和总价格
                2.9 商品数据入库
            
        
    """
    def create(self, validated_data):
        """保存订单"""

        #获取当前下单用户
        user = self.context['request'].user
        # 生成订单编号
        # 保存订单的基本信息数据 OrderInfo
        # 创建订单编号
        # 20180523160505+ user_id  100
        # timezone.now() -> datetime

        order_id = timezone.now().strftime('%Y%m%d%H%M%S') + ('%09d'%user.id)



        # 保存订单基本信息数据 OrderInfo
        address = validated_data['address']
        pay_method = validated_data['pay_method']

        with transaction.atomic():
            #创建一个保存点
            save_id = transaction.savepoint()

            try:
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('0'),
                    freight=Decimal('10.0'),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNSEND'] if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNPAID']
                )

                # 从redis中获取购物车结算商品数据
                redis_conn = get_redis_connection('cart')
                cart_redis = redis_conn.hgetall('cart_%s' % user.id)
                cart_selected = redis_conn.smembers('cart_selected_%s' % user.id)
                # 遍历结算商品：
                cart = {}
                for sku_id in cart_selected:
                    cart[int(sku_id)] = int(cart_redis[sku_id])

                sku_id_list = cart.keys()

                for sku_id in sku_id_list:
                    # 出现对于同一个商品的争抢下单时，如失败，再次尝试，直到库存不足
                    while True:
                        sku = SKU.objects.get(pk=sku_id)
                        # 判断商品库存是否充足
                        count = cart[sku.id]
                        if sku.stock < count:
                            transaction.savepoint_rollback(save_id)
                            raise serializers.ValidationError('库存不足')

                        print(sku.stock)
                        import time
                        time.sleep(5)
                        # 减少商品库存，增加商品销量
                        # sku.stock -= count
                        # sku.sales += count
                        # sku.save()

                        origin_stock = sku.stock

                        origin_sales = sku.sales

                        new_stock = origin_stock - count
                        new_sales = origin_sales + count

                        #返回受影响的行数
                        ret = SKU.objects.filter(id=sku.id,stock=origin_stock).update(stock=new_stock,sales=new_sales)
                        if ret == 0:
                            continue

                        # 保存订单商品数据
                        order.total_count += count
                        order.total_amount += (sku.price * count)

                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=count,
                            price=sku.price
                        )
                        #记得 break
                        break

                order.save()

            except ValueError:
                raise
            except Exception as e:
                transaction.savepoint_rollback(save_id)
                raise serializers.ValidationError('下单失败')

            #提交失误
            transaction.savepoint_commit(save_id)

            # 清除购物车中已经结算的商品
            pl = redis_conn.pipeline()
            pl.hdel('cart_%s' % user.id, *cart_selected)
            pl.srem('cart_selected_%s' % user.id, *cart_selected)
            pl.execute()

            return order